/*
 * The Apache Software License, Version 1.1 Copyright (c) 1999 The Apache Software Foundation. All
 * rights reserved. Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met: 1. Redistributions of source code
 * must retain the above copyright notice, this list of conditions and the following disclaimer. 2.
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
 * and the following disclaimer in the documentation and/or other materials provided with the
 * distribution. 3. The end-user documentation included with the redistribution, if any, must
 * include the following acknowlegement: "This product includes software developed by the Apache
 * Software Foundation (http://www.apache.org/)." Alternately, this acknowlegement may appear in the
 * software itself, if and wherever such third-party acknowlegements normally appear. 4. The names
 * "The Jakarta Project", "Tomcat", and "Apache Software Foundation" must not be used to endorse or
 * promote products derived from this software without prior written permission. For written
 * permission, please contact apache@apache.org. 5. Products derived from this software may not be
 * called "Apache" nor may "Apache" appear in their names without prior written permission of the
 * Apache Group. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
 * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ==================================================================== This software consists of
 * voluntary contributions made by many individuals on behalf of the Apache Software Foundation. For
 * more information on the Apache Software Foundation, please see <http://www.apache.org/>.
 * [Additional notices, if required by prior licensing conditions]
 */

package org.apache.catalina.util;

import java.text.MessageFormat;
import java.util.Hashtable;
import java.util.ResourceBundle;

/**
 * An internationalization / localization helper class which reduces the bother of handling
 * ResourceBundles and takes care of the common cases of message formating which otherwise require
 * the creation of Object arrays and such.
 * <p>
 * The StringManager operates on a package basis. One StringManager per package can be created and
 * accessed via the getManager method call.
 * <p>
 * The StringManager will look for a ResourceBundle named by the package name given plus the suffix
 * of "LocalStrings". In practice, this means that the localized information will be contained in a
 * LocalStrings.properties file located in the package directory of the classpath.
 * <p>
 * Please see the documentation for java.util.ResourceBundle for more information.
 *
 * @author James Duncan Davidson [duncan@eng.sun.com]
 * @author James Todd [gonzo@eng.sun.com]
 */
public class StringManager {

    /**
     * The ResourceBundle for this StringManager.
     */
    private ResourceBundle bundle;

    /**
     * Creates a new StringManager for a given package. This is a private method and all access to
     * it is arbitrated by the static getManager method call so that only one StringManager per
     * package will be created.
     * 
     * @param packageName
     */
    private StringManager(String packageName) {
        String bundleName = packageName + ".LocalStrings";
        bundle = ResourceBundle.getBundle(bundleName);
    }

    /**
     * Get a string from the underlying resource bundle.
     * 
     * @param key
     * @return
     */
    public String getString(String key) {
        if (key == null) {
            String msg = "key is null";
            throw new NullPointerException(msg);
        }

        String str = null;

        try {
            str = bundle.getString(key);
        } catch (Exception e) {
            str = "Cannot find message associated with key '" + key + "'";
        }

        return str;
    }

    /**
     * Get a string from the underlying resource bundle and format it with the given set of
     * arguments
     * 
     * @param key
     * @param args
     * @return
     */
    public String getString(String key, Object[] args) {
        String iString = null;
        String value = getString(key);

        // this check for the runtime exception is some pre 1.1.6
        // VM's don't do an automatic toString() on the passed in
        // objects and barf out

        try {
            // ensure the arguments are not null so pre 1.2 VM's don't barf
            Object[] nonNullArgs = args;
            for (int i = 0; i < args.length; i++) {
                if (args[i] == null) {
                    if (nonNullArgs == args) {
                        nonNullArgs = args.clone();
                    }
                    nonNullArgs[i] = "null";
                }
            }

            iString = MessageFormat.format(value, nonNullArgs);
        } catch (IllegalArgumentException e) {
            StringBuffer buf = new StringBuffer();
            buf.append(value);
            for (int i = 0; i < args.length; i++) {
                buf.append(" args[" + i + "]=" + args[i]);
            }
            iString = buf.toString();
        }
        return iString;
    }

    /**
     * Get a string from the underlying resource bundle and format it with the given object
     * argument. This argument can of course be a String object.
     * 
     * @param key
     * @param arg
     * @return
     */
    public String getString(String key, Object arg) {
        Object[] args = new Object[] { arg };
        return getString(key, args);
    }

    /**
     * Get a string from the underlying resource bundle and format it with the given object
     * arguments. These arguments can of course be String objects.
     *
     * @param key
     * @param arg1
     * @param arg2
     */
    public String getString(String key, Object arg1, Object arg2) {
        Object[] args = new Object[] { arg1, arg2 };
        return getString(key, args);
    }

    /**
     * Get a string from the underlying resource bundle and format it with the given object
     * arguments. These arguments can of course be String objects.
     *
     * @param key
     * @param arg1
     * @param arg2
     * @param arg3
     */
    public String getString(String key, Object arg1, Object arg2,
            Object arg3) {
        Object[] args = new Object[] { arg1, arg2, arg3 };
        return getString(key, args);
    }

    /**
     * Get a string from the underlying resource bundle and format it with the given object
     * arguments. These arguments can of course be String objects.
     *
     * @param key
     * @param arg1
     * @param arg2
     * @param arg3
     * @param arg4
     */
    public String getString(String key, Object arg1, Object arg2,
            Object arg3, Object arg4) {
        Object[] args = new Object[] { arg1, arg2, arg3, arg4 };
        return getString(key, args);
    }

    // --------------------------------------------------------------
    // STATIC SUPPORT METHODS
    // --------------------------------------------------------------

    private static Hashtable managers = new Hashtable();

    public synchronized static StringManager getManager(String packageName) {
        StringManager mgr = (StringManager) managers.get(packageName);
        if (mgr == null) {
            mgr = new StringManager(packageName);
            managers.put(packageName, mgr);
        }
        return mgr;
    }

}